/**
 * Copyright(c) 2014 Xunton Solutions
 *
 * History:
 *   15-11-14 下午5:35 Created by dwzhang
 */
package com.jade.modules.message.mail.impl;

import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import com.jade.framework.base.log.Log;
import com.jade.framework.base.log.LogUtils;
import com.jade.modules.message.mail.MailClient;
import com.jade.modules.message.mail.MailStatus;
import org.apache.commons.lang3.StringUtils;

/**
 * 采用JAVA MAIL中的Transport来发送邮件。
 *
 * @author <a href="mailto:dwzhang@xunton.com">dwzhang</a> 
 * @version 1.0 15-11-14 下午5:35
 */
public class SimpleMailClient
        implements MailClient
{
    private final transient Properties props = System.getProperties();
    private String server;
    private int port = 25;
    private int sslPort;
    private boolean enableSsl = false;
    private String username;
    private String password;
    private Session session;
    private String defaultFromAddress;
    private String defaultFromName;
    private Address defaultFrom;
    private Log log = LogUtils.getLog(SimpleMailClient.class);

    public SimpleMailClient(String server, int port, String username, String password)
    {
        this(server, port, username, password, false, 0);
    }

    public SimpleMailClient(String server, int port, String username, String password, boolean enableSsl, int sslPort)
    {
        this.server = server;
        this.port = port;
        this.username = username;
        this.password = password;
        this.enableSsl = enableSsl;
        this.sslPort = sslPort;
    }

    @PostConstruct
    public void init()
    {
        props.setProperty("mail.transport.protocol", "smtp");
        props.setProperty("mail.smtp.host", server);
        props.setProperty("mail.smtp.port", String.valueOf(port));
        props.setProperty("mail.smtp.auth", String.valueOf(true));
        session = Session.getDefaultInstance(props, new SimpleAuthenticator(username, password));
        if (enableSsl) {
            enableSSL(sslPort);
        }

        if (StringUtils.isBlank(defaultFromAddress)) {
            defaultFromAddress = username;
        }
        try {
            if (StringUtils.isNotBlank(defaultFromName)) {
                defaultFrom = new InternetAddress(defaultFromAddress, defaultFromName);
            }
            else {
                defaultFrom = new InternetAddress(defaultFromAddress);
            }
        }
        catch (Exception e) {
            log.warnThrowable("Can't create default sender:", (Throwable) e);
        }
    }

    public void setServer(String server)
    {
        this.server = server;
    }

    public void setPort(int port)
    {
        this.port = port;
    }

    public void setUsername(String username)
    {
        this.username = username;
    }

    public void setPassword(String password)
    {
        this.password = password;
    }

    public int getSslPort()
    {
        return sslPort;
    }

    public void setSslPort(int sslPort)
    {
        this.sslPort = sslPort;
    }

    public boolean isEnableSsl()
    {
        return enableSsl;
    }

    public void setEnableSsl(boolean enableSsl)
    {
        this.enableSsl = enableSsl;
    }

    public String getDefaultFromAddress()
    {
        return defaultFromAddress;
    }

    public void setDefaultFromAddress(String defaultFromAddress)
    {
        this.defaultFromAddress = defaultFromAddress;
    }

    public String getDefaultFromName()
    {
        return defaultFromName;
    }

    public void setDefaultFromName(String defaultFromName)
    {
        this.defaultFromName = defaultFromName;
    }

    private void enableSSL(int sslPort)
    {
        props.setProperty("mail.smtp.socketFactory.class",
                "javax.net.ssl.SSLSocketFactory");
        props.setProperty("mail.smtp.socketFactory.fallback", "false");
        props.setProperty("mail.smtp.port", String.valueOf(sslPort));
        props.setProperty("mail.smtp.socketFactory.port", String.valueOf(sslPort));
    }

    protected void setFrom(MimeMessage message)
            throws MessagingException
    {
        if (message.getFrom() == null && defaultFrom != null) {
            message.setFrom(defaultFrom);
        }
    }

    public int sendMail(String subject, Object content, String recipient)
    {
        MimeMessage message = createMessage();
        try {
            message.addRecipient(Message.RecipientType.TO, new InternetAddress(recipient));
            message.setSubject(subject);
            message.setContent(content, "text/html;charset=UTF-8");
        }
        catch (Exception e) {
            log.debugThrowable("Can't create message:", e);
            return MailStatus.SC_INVALID_MESSAGE;
        }
        return sendMail(message);
    }

    public int sendMail(String subject, Object content, Address[] recipients)
    {
        MimeMessage message = createMessage();
        try {
            message.addRecipients(Message.RecipientType.TO, recipients);
            message.setSubject(subject);
            message.setContent(content, "text/html;charset=UTF-8");
        }
        catch (Exception e) {
            log.debugThrowable("Can't create message:", e);
            return MailStatus.SC_INVALID_MESSAGE;
        }
        return sendMail(message);
    }

    public int sendMail(MimeMessage message)
    {
        try {
            setFrom(message);
            message.saveChanges();
        }
        catch (MessagingException e) {
            log.debugThrowable("Can't create message:", e);
            return MailStatus.SC_INVALID_MESSAGE;
        }
        try {
            Transport.send(message);
            return MailStatus.SC_OK;
        }
        catch (MessagingException e) {
            log.debugThrowable("Can't transport message:", e);
            return MailStatus.SC_SERVER_ERROR;
        }
    }

    public int sendMail(MimeMessage message, Address[] recipients)
    {
        try {
            setFrom(message);
            message.saveChanges();
        }
        catch (MessagingException e) {
            log.debugThrowable("Can't create message:", e);
            return MailStatus.SC_INVALID_MESSAGE;
        }
        try {
            Transport.send(message, recipients);
            return MailStatus.SC_OK;
        }
        catch (SendFailedException e) {
            log.debugThrowable("Can't transport message:", e);
            return MailStatus.SC_SERVER_ERROR;
        }
        catch (MessagingException e) {
            log.debugThrowable("Can't transport message:", e);
            return MailStatus.SC_NETWORK_ERROR;
        }
    }

    public MimeMessage createMessage()
    {
        return new MimeMessage(session);
    }
}
